package com.crypto;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

public class AsymmetricCryptor {

	private PublicKey publicKey = null;
	private PrivateKey privateKey = null;

	private static String ALGORITHM = "RSA";
	private static int KEY_BYTES=1024;

	public static void main(String[] args) {
		AsymmetricCryptor ac = new AsymmetricCryptor(true);
		String k=new String(Base64.encodeBase64(ac.getPrivateKey().getEncoded()));
		System.out.println(k);
		System.out.println("--------------------");
		k=new String(Base64.encodeBase64(ac.getPublicKey().getEncoded()));
		System.out.println(k);
		System.out.println("--------------------");
		String text = "Hallo du Pfeife";
		byte[] encodedByte = ac.encrypt(text);
		String encodedString = new String(encodedByte);
		System.out.println(encodedString);
		System.out.println(new String(ac.decrypt(encodedByte)));
		System.out.println("--------------------");
		
		File fpriv=new File("D://key.priv");
		File fpub=new File("D://key.pub");
		ac.writePrivateKey(fpriv);
		ac.writePublicKey(fpub);
		PrivateKey pk=ac.readPrivateKey(fpriv);

		System.out.println("--------------------");
		System.out.println(new String(ac.getPrivateKey().getEncoded()).equals(new String(pk.getEncoded())));
		System.out.println("--------------------");

		
	}

	public AsymmetricCryptor(boolean createNewKeys) {
		if(createNewKeys)
			generateKey();
	}

	private void generateKey() {
		try {
			KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
			kpg.initialize(KEY_BYTES);
			KeyPair keyPair = kpg.genKeyPair();
			this.privateKey = keyPair.getPrivate();
			this.publicKey = keyPair.getPublic();
		} catch (NoSuchAlgorithmException e) {
			System.out.println("" + e.getMessage());
		}
	}

	/**
	 * Encrypt the plain text using public key.
	 * 
	 * @param text
	 *            : original plain text
	 * @param key
	 *            :The public key
	 * @return Encrypted text
	 * @throws java.lang.Exception
	 */
	public byte[] encrypt(String text) {
		byte[] base64text = null;
		try {
			// get an RSA cipher object and print the provider
			final Cipher cipher = Cipher.getInstance(ALGORITHM);
			// encrypt the plain text using the public key
			cipher.init(Cipher.ENCRYPT_MODE, this.publicKey);
			byte[] cipherText = cipher.doFinal(text.getBytes());
			base64text = Base64.encodeBase64(cipherText);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return base64text;
	}

	/**
	 * Decrypt text using private key.
	 * 
	 * @param text
	 *            :encrypted text
	 * @param key
	 *            :The private key
	 * @return plain text
	 * @throws java.lang.Exception
	 */
	public String decrypt(byte[] text) {
		byte[] dectyptedText = null;
		try {
			// get an RSA cipher object and print the provider
			final Cipher cipher = Cipher.getInstance(ALGORITHM);

			byte[] base64text = Base64.decodeBase64(text);

			// decrypt the text using the private key
			cipher.init(Cipher.DECRYPT_MODE, this.privateKey);
			dectyptedText = cipher.doFinal(base64text);
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return new String(dectyptedText);
	}

	public void writePrivateKey(File f) {
		FileOutputStream out;
		try {
			out = new FileOutputStream(f);
			byte[] ky = this.privateKey.getEncoded();
			byte[] base64Key = Base64.encodeBase64(ky);
			out.write(base64Key);
			out.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

	public void writePublicKey(File f) {
		FileOutputStream out;
		try {
			out = new FileOutputStream(f);
			byte[] ky = this.publicKey.getEncoded();
			byte[] base64Key = Base64.encodeBase64(ky);
			out.write(base64Key);
			out.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	
	public PublicKey readPublicKey(File f){
		PublicKey pubKey=null;
        try {
        	KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            FileInputStream pubKeyStream = new FileInputStream(f);  
            byte[] pubKeyBytes = new byte[KEY_BYTES]; // 1024 bits  
			pubKeyStream.read(pubKeyBytes);
			pubKeyStream.close();  
			byte[] base64Key = Base64.decodeBase64(pubKeyBytes);
	        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(base64Key);  
	        pubKey = keyFactory.generatePublic(pubKeySpec); 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}  
         
        return pubKey;
	}
	
	
	public PrivateKey readPrivateKey(File f){
		PrivateKey privKey=null;
        try {
        	KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            FileInputStream pubKeyStream = new FileInputStream(f);  
            byte[] privKeyBytes = new byte[KEY_BYTES]; // 1024 bits  
			pubKeyStream.read(privKeyBytes);
			pubKeyStream.close();   
			byte[] base64Key = Base64.decodeBase64(privKeyBytes);
			PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(base64Key);  
	        privKey = keyFactory.generatePrivate(priKeySpec);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}  
         
        return privKey;
	}
	
	
	public PrivateKey readPrivateKey(String key64){
		PrivateKey privKey=null;
        try {
        	KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            byte[] privKeyBytes = key64.getBytes();
			byte[] base64Key = Base64.decodeBase64(privKeyBytes);
			PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(base64Key);  
	        privKey = keyFactory.generatePrivate(priKeySpec);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}  
         
        return privKey;
	}
	
	public PublicKey readPublicKey(String key64){
		PublicKey pubKey=null;
        try {
        	KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
            byte[] pubKeyBytes = key64.getBytes(); 
            byte[] base64Key = Base64.decodeBase64(pubKeyBytes);
	        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(base64Key);  
	        pubKey = keyFactory.generatePublic(pubKeySpec); 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}  
         
        return pubKey;
	}

	public PublicKey getPublicKey() {
		return publicKey;
	}

	public void setPublicKey(PublicKey publicKey) {
		this.publicKey = publicKey;
	}

	public PrivateKey getPrivateKey() {
		return privateKey;
	}

	public void setPrivateKey(PrivateKey privateKey) {
		this.privateKey = privateKey;
	}

}
